package nl.zoidberg.calculon.engine;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;

import nl.zoidberg.calculon.model.Board;
import nl.zoidberg.calculon.model.Game;
import nl.zoidberg.calculon.model.Piece;

public class MoveGenerator {
	
	private static MoveGenerator instance = new MoveGenerator();
	private static Map<Byte, PieceMoveGenerator> generatorMap = new HashMap<Byte, PieceMoveGenerator>();
	static {
		generatorMap.put(Piece.PAWN, 	new PawnMoveGenerator());
		generatorMap.put(Piece.KNIGHT, 	new KnightMoveGenerator());
		generatorMap.put(Piece.BISHOP, 	new BishopMoveGenerator());
		generatorMap.put(Piece.ROOK, 	new RookMoveGenerator());
		generatorMap.put(Piece.QUEEN, 	new QueenMoveGenerator());
		generatorMap.put(Piece.KING, 	new KingMoveGenerator());
	}
	
	public static MoveGenerator get() {
		return instance;
	}

	private MoveGenerator() { }
	
	public boolean isMovePossible(Board board) {
		for(int file = 0; file < 8; file++) {
			for(int rank = 0; rank < 8; rank++) {
				byte piece = board.getPiece(file, rank);
				if((piece & Piece.MASK_TYPE) != Piece.EMPTY && (piece & Piece.MASK_COLOR) == board.getPlayer()) {
					byte type = (byte) (board.getPiece(file, rank) & Piece.MASK_TYPE);
					Map<String, SearchNode> moves = generatorMap.get(type).generateMoves(board, file, rank, true);
					if(moves.size() > 0) {
						return true;
					}
				}
			}
		}
		return false;
	}
	
	public Map<String, SearchNode> generateMoves(Board board) {
		Map<String, SearchNode> rv = new TreeMap<String, SearchNode>();
		
		if(board == null || board.getResult() != Game.RES_NO_RESULT) {
			return rv;
		}
		
		for(int file = 0; file < 8; file++) {
			for(int rank = 0; rank < 8; rank++) {
				byte piece = board.getPiece(file, rank);
				if((piece & Piece.MASK_TYPE) != Piece.EMPTY && (piece & Piece.MASK_COLOR) == board.getPlayer()) {
					byte type = (byte) (board.getPiece(file, rank) & Piece.MASK_TYPE);
					rv.putAll(generatorMap.get(type).generateMoves(board, file, rank));
				}
			}
		}
		
		return rv;
	}

	public Map<String, List<String>> getPossibleMoves(Board board) {
		Map<String, List<String>> moves = new HashMap<String, List<String>>();
		for(String move: MoveGenerator.get().generateMoves(board).keySet()) {
			if("O-O".equals(move)) {
				move = board.getPlayer() == Piece.WHITE ? "E1G1" : "E8G8";
			}
			if("O-O-O".equals(move)) {
				move = board.getPlayer() == Piece.WHITE ? "E1C1" : "E8C8";
			}
			String from = move.substring(0, 2);
			if(moves.get(from) == null) {
				moves.put(from, new ArrayList<String>());
			}
			List<String> toList = moves.get(from);
			toList.add(move.substring(2));
		}
		return moves;
	}
}
